package com.rent.common.interceptor;

import com.rent.common.constant.CommonConstant;
import com.rent.common.entity.ResponseResult;
import com.rent.common.util.JsonUtils;
import com.rent.common.util.JwtUtil;
import com.rent.common.util.RedisUtil;
import com.rent.common.util.ResponseUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * JWT拦截器
 * 拦截请求，验证Token，将用户信息存入ThreadLocal
 */
@Slf4j
@Component
public class JwtInterceptor implements HandlerInterceptor {
    @Autowired
    private RedisUtil redisUtil;
    
    /**
     * 前置处理：验证Token
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 
            throws Exception {
        // 放行 OPTIONS 请求（CORS 预检）
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            return true; // 直接放行，不进行 JWT 验证
        }

        // 从请求头获取Token
        String token = getTokenFromRequest(request);
        
        // Token为空
        if (token == null || token.isEmpty()) {
            log.warn("Token为空，请求路径：{}", request.getRequestURI());
            ResponseResult<Void> result = ResponseResult.unauthorized("请先登录");
            ResponseUtils.responseToJson(response, JsonUtils.objectToJson(result));
            return false;
        }
        
        // 验证Token
        if (!JwtUtil.verify(token)) {
            log.warn("Token验证失败，请求路径：{}", request.getRequestURI());
            ResponseResult<Void> result = ResponseResult.unauthorized("Token无效或已过期");
            ResponseUtils.responseToJson(response, JsonUtils.objectToJson(result));
            return false;
        }
        
        // 判断是否过期
        if (JwtUtil.isExpired(token)) {
            log.warn("Token已过期，请求路径：{}", request.getRequestURI());
            ResponseResult<Void> result = ResponseResult.unauthorized("Token已过期，请重新登录");
            ResponseUtils.responseToJson(response, JsonUtils.objectToJson(result));
            return false;
        }

        // 解析Token，获取用户信息
        try {
            Map<String, Object> userInfo = JwtUtil.parseToken(token);
            if (userInfo != null) {
                Long userId = (Long) userInfo.get("userId");
                String username = (String) userInfo.get("username");
                Integer role = (Integer) userInfo.get("role");
                
                // 存入ThreadLocal
                UserContext.setUser(new UserContext.UserInfo(userId, username, role));

                // 单点登录冲突检测
                String oldTokenKey = "user:id:" + userId;
                String oldToken = (String) redisUtil.get(oldTokenKey);
                if (oldToken != null && !oldToken.equals(token)) {
                    log.warn("Token已过期，请求路径：{}", request.getRequestURI());
                    ResponseResult<Void> result = ResponseResult.unauthorized("Token已过期，请重新登录");
                    ResponseUtils.responseToJson(response, JsonUtils.objectToJson(result));
                    return false;
                }

                log.debug("Token验证成功，userId: {}, username: {}", userId, username);
                return true;
            } else {
                log.warn("Token解析失败，请求路径：{}", request.getRequestURI());
                ResponseResult<Void> result = ResponseResult.unauthorized("Token解析失败");
                ResponseUtils.responseToJson(response, JsonUtils.objectToJson(result));
                return false;
            }
        } catch (Exception e) {
            log.error("Token解析异常", e);
            ResponseResult<Void> result = ResponseResult.unauthorized("Token解析异常");
            ResponseUtils.responseToJson(response, JsonUtils.objectToJson(result));
            return false;
        }
    }
    
    /**
     * 完成处理：清理ThreadLocal
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, 
                                Object handler, Exception ex) throws Exception {
        // 清理ThreadLocal，防止内存泄漏
        UserContext.clear();
    }
    
    /**
     * 从请求中获取Token
     * 支持两种方式：
     * 1. Authorization: Bearer {token}
     * 2. token: {token}
     */
    private String getTokenFromRequest(HttpServletRequest request) {
        // 方式1：从Authorization头获取
        String authorization = request.getHeader(CommonConstant.TOKEN_HEADER);
        if (authorization != null && authorization.startsWith(CommonConstant.TOKEN_PREFIX)) {
            return authorization.substring(CommonConstant.TOKEN_PREFIX.length());
        }
        
        // 方式2：从token头获取
        String token = request.getHeader("token");
        if (token != null && !token.isEmpty()) {
            return token;
        }
        
        return null;
    }
}

